using System;
using System.Collections.Generic;
using UnityEngine;

public class LevelSystem : ScriptableObject
{
	[Serializable]
	public class DefinedPoints
	{
		public int level;

		private int _totalStars;

		public string levelName;

		public int starsNeededToNextLevel;

		public int totalStars
		{
			get
			{
				return _totalStars;
			}
		}

		public void Init(int totalStars)
		{
			_totalStars = totalStars;
		}
	}

	[Serializable]
	public class QuadraticReferencePoint
	{
		public int totalXPAtLevel;

		public int level;
	}

	[Serializable]
	public class LevelDefinition
	{
		public float skillPointsToNextLevel = 5f;
	}

	public struct LevelInfo
	{
		public int levelIndex;

		public float subLevelProgress;

		public LevelDefinition definition;
	}

	[Serializable]
	public class SkillLevelDefinition
	{
		public PlayerStatsManager.SkillType skillType;

		public List<LevelDefinition> levels = new List<LevelDefinition>();

		public LevelInfo GetLevelForSkillPoints(float skillPoints)
		{
			float num = 0f;
			int num2 = 0;
			LevelInfo result = default(LevelInfo);
			foreach (LevelDefinition level in levels)
			{
				float num3 = num;
				num += level.skillPointsToNextLevel;
				if (num > skillPoints)
				{
					result.levelIndex = num2;
					result.definition = level;
					result.subLevelProgress = (skillPoints - num3) / level.skillPointsToNextLevel;
					return result;
				}
				num2++;
			}
			LevelDefinition levelDefinition = levels[levels.Count - 1];
			float num4 = (skillPoints - num) / levelDefinition.skillPointsToNextLevel;
			num2 += Mathf.FloorToInt(num4);
			result.definition = levelDefinition;
			result.levelIndex = num2;
			result.subLevelProgress = num4 - (float)Mathf.FloorToInt(num4);
			return result;
		}
	}

	[Serializable]
	public class AttributeLevelReferenceInfo
	{
		public QuadraticReferencePoint referencePoint;

		public PlayerStatsManager.AttributeType attrType;
	}

	[Serializable]
	public class SkillLevelReferenceInfo
	{
		public QuadraticReferencePoint referencePoint;

		public PlayerStatsManager.SkillType skillType;
	}

	public struct CurrentDefinedPointLevelInfo
	{
		public int levelIndex;

		public DefinedPoints definedPoint;

		public float subProgress;

		public int totalCollectedStars;
	}

	protected static LevelSystem instance_;

	public List<DefinedPoints> points = new List<DefinedPoints>();

	public QuadraticReferencePoint maxPlayerLevel;

	public List<SkillLevelDefinition> levelDefinitions = new List<SkillLevelDefinition>();

	public int xpPerMatch = 5;

	public int xpPerAttributeTraining = 3;

	public int xpPerMinigame = 4;

	public int xpPerSocial = 2;

	public List<AttributeLevelReferenceInfo> attributeRefencePoints = new List<AttributeLevelReferenceInfo>();

	public List<SkillLevelReferenceInfo> skillReferencePoints = new List<SkillLevelReferenceInfo>();

	public static LevelSystem instance
	{
		get
		{
			if (instance_ == null)
			{
				instance_ = Resources.Load("LevelSystem", typeof(LevelSystem)) as LevelSystem;
				instance_.Init();
			}
			return instance_;
		}
	}

	public void Init()
	{
		int num = 0;
		foreach (DefinedPoints point in points)
		{
			point.Init(num);
			num += point.starsNeededToNextLevel;
		}
	}

	public SkillLevelDefinition GetSkillLevelDefinition(PlayerStatsManager.SkillType skillType)
	{
		foreach (SkillLevelDefinition levelDefinition in levelDefinitions)
		{
			if (levelDefinition.skillType == skillType)
			{
				return levelDefinition;
			}
		}
		return null;
	}

	private float GetQuadraticParametrisationFactor(QuadraticReferencePoint referencePoint)
	{
		return Mathf.Sqrt(referencePoint.totalXPAtLevel) / (float)referencePoint.level;
	}

	private int GetLevelPointDefinitionIndex(int xp)
	{
		if (maxPlayerLevel.totalXPAtLevel <= xp)
		{
			return points.Count - 1;
		}
		float quadraticParametrisationFactor = GetQuadraticParametrisationFactor(maxPlayerLevel);
		for (int i = 0; i < points.Count; i++)
		{
			int num = Mathf.CeilToInt(Mathf.Pow((float)points[i].level * quadraticParametrisationFactor, 2f));
			if (xp < num)
			{
				return Mathf.Max(0, i - 1);
			}
		}
		return -1;
	}

	public string FindLevelName(int xp)
	{
		int levelPointDefinitionIndex = GetLevelPointDefinitionIndex(xp);
		return points[levelPointDefinitionIndex].levelName;
	}

	public CurrentDefinedPointLevelInfo PlayerLevelForXP(int totalStars)
	{
		int num = FindLevelForXP(totalStars);
		DefinedPoints definedPoints = points[num];
		float subProgress = Mathf.InverseLerp(definedPoints.totalStars, definedPoints.totalStars + definedPoints.starsNeededToNextLevel, totalStars);
		CurrentDefinedPointLevelInfo result = default(CurrentDefinedPointLevelInfo);
		result.levelIndex = num;
		result.definedPoint = definedPoints;
		result.subProgress = subProgress;
		result.totalCollectedStars = totalStars;
		return result;
	}

	public CurrentDefinedPointLevelInfo CurrentPlayerLevel()
	{
		int totalStars = SingletonInit<PlayerCareer>.Instance.TotalNumberOfStars();
		return PlayerLevelForXP(totalStars);
	}

	public int FindLevelForXP(int xp)
	{
		int num = 0;
		foreach (DefinedPoints point in points)
		{
			if (xp < point.totalStars + point.starsNeededToNextLevel)
			{
				break;
			}
			num++;
		}
		return Mathf.Min(num, points.Count - 1);
	}

	public int GetXPForLevel(int level)
	{
		DefinedPoints definedPoints = points[Mathf.Clamp(level, 0, points.Count - 1)];
		return definedPoints.totalStars;
	}

	public bool IsMaxLevelReached(int xp)
	{
		return xp >= maxPlayerLevel.totalXPAtLevel;
	}

	public LevelInfo GetSkillLevelInfo(PlayerStatsManager.SkillType skillType, float currentSkillPoints)
	{
		SkillLevelDefinition skillLevelDefinition = GetSkillLevelDefinition(skillType);
		if (skillLevelDefinition == null)
		{
			return default(LevelInfo);
		}
		return skillLevelDefinition.GetLevelForSkillPoints(currentSkillPoints);
	}

	public int GetSkillPointsValForLevel(PlayerStatsManager.SkillType skillType, int level)
	{
		SkillLevelReferenceInfo skillReferencePoint = GetSkillReferencePoint(skillType);
		if (skillReferencePoint == null)
		{
			return 0;
		}
		float quadraticParametrisationFactor = GetQuadraticParametrisationFactor(skillReferencePoint.referencePoint);
		return Mathf.Min(Mathf.CeilToInt(Mathf.Pow((float)level * quadraticParametrisationFactor, 2f)), skillReferencePoint.referencePoint.totalXPAtLevel);
	}

	private SkillLevelReferenceInfo GetSkillReferencePoint(PlayerStatsManager.SkillType skillType)
	{
		foreach (SkillLevelReferenceInfo skillReferencePoint in skillReferencePoints)
		{
			if (skillReferencePoint.skillType == skillType)
			{
				return skillReferencePoint;
			}
		}
		return null;
	}

	public int GetAttributeValue(PlayerStatsManager.AttributeType attrType, float currentAttrPoints)
	{
		AttributeLevelReferenceInfo attributeReferencePoint = GetAttributeReferencePoint(attrType);
		if (attributeReferencePoint == null)
		{
			return 0;
		}
		float quadraticParametrisationFactor = GetQuadraticParametrisationFactor(attributeReferencePoint.referencePoint);
		int a = Mathf.FloorToInt(Mathf.Sqrt(currentAttrPoints) / quadraticParametrisationFactor);
		return Mathf.Min(a, attributeReferencePoint.referencePoint.level);
	}

	public int GetAttrPointsValForLevel(PlayerStatsManager.AttributeType attrType, int level)
	{
		AttributeLevelReferenceInfo attributeReferencePoint = GetAttributeReferencePoint(attrType);
		if (attributeReferencePoint == null)
		{
			return 0;
		}
		float quadraticParametrisationFactor = GetQuadraticParametrisationFactor(attributeReferencePoint.referencePoint);
		return Mathf.Min(Mathf.CeilToInt(Mathf.Pow((float)level * quadraticParametrisationFactor, 2f)), attributeReferencePoint.referencePoint.totalXPAtLevel);
	}

	private AttributeLevelReferenceInfo GetAttributeReferencePoint(PlayerStatsManager.AttributeType attrType)
	{
		foreach (AttributeLevelReferenceInfo attributeRefencePoint in attributeRefencePoints)
		{
			if (attributeRefencePoint.attrType == attrType)
			{
				return attributeRefencePoint;
			}
		}
		return null;
	}

	public int GetLevelForName(string levelName)
	{
		foreach (DefinedPoints point in points)
		{
			if (point.levelName == levelName)
			{
				return point.level;
			}
		}
		return -1;
	}
}
